package com.huan.es8.aggregations.bucket;

import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.util.NamedValue;
import com.huan.es8.AbstractEs8Api;
import org.junit.jupiter.api.*;

import java.io.IOException;
import java.util.Arrays;

/**
 * 直方图聚合
 * @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html">官方文档</a>
 * @see <a href="https://blog.csdn.net/fu_huo_1993/article/details/128008665">博客地址</a>
 * @author huan.fu
 * @date 2022/11/23 - 22:22
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HistogramAggs extends AbstractEs8Api {

    // @BeforeAll
    public void createIndex() throws IOException {
        createIndex("index_api_response_time",
                "{\n" +
                        "  \"settings\": {\n" +
                        "    \"number_of_shards\": 1\n" +
                        "  },\n" +
                        "  \"mappings\": {\n" +
                        "    \"properties\": {\n" +
                        "      \"id\": {\n" +
                        "        \"type\": \"long\"\n" +
                        "      },\n" +
                        "      \"api\": {\n" +
                        "        \"type\": \"keyword\"\n" +
                        "      },\n" +
                        "      \"response_time\": {\n" +
                        "        \"type\": \"integer\"\n" +
                        "      }\n" +
                        "    }\n" +
                        "  }\n" +
                        "}");

        bulk("index_api_response_time", Arrays.asList(
                "{\"api\":\"/user/infos\",\"response_time\": 3}",
                "{\"api\":\"/user/add\"}",
                "{\"api\":\"/user/update\",\"response_time\": 8}",
                "{\"api\":\"/user/list\",\"response_time\": 15}",
                "{\"api\":\"/user/export\",\"response_time\": 30}",
                "{\"api\":\"/user/detail\",\"response_time\": 32}"
        ));
    }

    @Test
    @DisplayName("根据response_time聚合，间隔为5")
    public void test01() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .aggregations("agg_01", agg -> agg.histogram(histogram -> histogram.field("response_time")
                                .interval(5D))));
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("在test01基础上聚合出每个桶总的响应时间")
    public void test02() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .aggregations("agg_01", agg ->
                                agg.histogram(histogram -> histogram.field("response_time").interval(5D))
                                   .aggregations("agg_sum", aggSum -> aggSum.sum(sum -> sum.field("response_time")))
                        ));
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("每个桶中必须存在1个文档的结果才返回-min_doc_count")
    public void test03() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .aggregations("agg_01", agg -> agg.histogram(
                                histogram -> histogram.field("response_time").interval(5D).minDocCount(1)
                                )
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("补充空桶数据-extended_bounds")
    public void test04() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
                        .aggregations("agg_01", agg -> agg.histogram(
                                histogram -> histogram.field("response_time").interval(5D).minDocCount(0)
                                        .extendedBounds(bounds -> bounds.min(1D).max(50D))
                                )
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("只展示min-max之间的桶-hard_bounds")
    public void test05() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
                        .aggregations("agg_01", agg ->
                                agg.histogram(
                                    histogram -> histogram.field("response_time").interval(5D).minDocCount(0)
                                            .hardBounds(bounds -> bounds.min(1D).max(50D))
                                )
                                   .aggregations("a_s", sumAgg -> sumAgg.sum(sum -> sum.field("response_time")))
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("排序order")
    public void test06() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
                        .aggregations("agg_01", agg ->
                                agg.histogram(
                                    histogram -> histogram.field("response_time").interval(5D)
                                            .order(NamedValue.of("_count", SortOrder.Desc))
                                )
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("文档中缺失聚合字段时如何处理-missing")
    public void test07() throws IOException {
        SearchRequest request = SearchRequest.of(search ->
                search
                        .index("index_api_response_time")
                        .size(0)
                        .query(query-> query.range(range -> range.field("response_time").gte(JsonData.of(10))))
                        .aggregations("agg_01", agg ->
                                agg.histogram(
                                    histogram -> histogram.field("response_time").interval(5D) .missing(0D)
                                )
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }


    // @AfterAll
    public void deleteIndex() throws IOException {
        deleteIndex("index_api_response_time");
    }
}
